﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace MonoTouchAutoBind
{
    class BindMethod : MonotouchBind
    {
        private string patternStart = @"(?'IsStatic'[+-])\s*\((?'Return'[\w\s()<>^*]+)\)(?'FunctionName'(\s*\w+)|(\s*\w+\s*:\s*\(\s*[\w\s()<>^*,]+\s*\)\s*\w+)+)\s*;";
        private System.Text.RegularExpressions.Regex regex = null;


        private bool isStatic, noParam;
        public string ReturnType;
        public string FunctonNameAndParams = "";


        public override string EndString
        {
            get
            {
                return ";";
            }
        }

        public BindMethod()
            : base()
        {
            regex = new System.Text.RegularExpressions.Regex(patternStart);
        }

        public override bool CanParse(string code)
        {
            return regex.IsMatch(code);
        }

        public override int PushCode(string code)
        {
            this.ParseFiniseStatus = ParseStatus.Processing;
            this.BindCode = code;

            if (this.CanParse(code))
            {
                System.Text.RegularExpressions.Match match = regex.Match(code);
                isStatic = match.Groups["IsStatic"].Value.Equals("+") ? true : false;
                ReturnType = match.Groups["Return"].Value.Replace("*", "").Trim();
                FunctonNameAndParams = match.Groups["FunctionName"].Value.Trim();
                noParam = !FunctonNameAndParams.Contains(":");

                this.ParseFiniseStatus = ParseStatus.Finished;
                return match.Length;
            }
            else
            {
                this.ParseFiniseStatus = ParseStatus.Finished;
                DebugOut.Instance.Print(code);
                return 0;
            }
        }

        private List<methodNameParam> getParams()
        {

            List<methodNameParam> list = new List<methodNameParam>();
            Regex re = new Regex(@"(?'paramName'\w+)\s*:\s*\(\s*(?'paramType'[\w\s()<>^*,]+)\s*\)\s*(?'paramValue'\w+)", RegexOptions.None);
            MatchCollection mc = re.Matches(this.FunctonNameAndParams);
            foreach (Match ma in mc)
            {
                methodNameParam p = new methodNameParam()
                {
                    paramName = ma.Groups["paramName"].Value.Trim(),
                    paramType = ma.Groups["paramType"].Value.Replace("*", "").Trim(),
                    paramValue = ma.Groups["paramValue"].Value.Trim()
                };
                list.Add(p);
            }

            return list;
        }

        public override string GenerateCSharp()
        {


            /*
            [Static, Export("cellForGridView:")]
            KKGridViewCell CellFroGridView(KKGridView gridView);
            */

            StringBuilder sb = new StringBuilder();
            sb.Append("\t");
            sb.AppendFormat("//{0}", this.BindCode);
            sb.AppendLine();
            sb.Append("\t");
            sb.Append("[");
            if (this.isStatic)
                sb.Append("Static,");

            if (this.noParam)
            {
                sb.AppendFormat("Export(\"{0}\")", this.FunctonNameAndParams);
                sb.AppendLine("]");
                sb.Append("\t");
                if (this.ReturnType.Equals("id") && this.FunctonNameAndParams.StartsWith("init"))
                {
                    sb.AppendFormat("{0} {1}();", "IntPtr", "Constructor");
                }
                else
                {
                    sb.AppendFormat("{0} {1}();", this.ReturnType, this.FunctonNameAndParams);
                }
            }
            else
            {
                List<methodNameParam> list = getParams();

                string reType = this.ReturnType;
                string functionName = list[0].paramName;
                if (this.ReturnType.Equals("id") && this.FunctonNameAndParams.StartsWith("init"))
                {
                    reType = "IntPtr";
                    functionName = "Constructor";
                }

                sb.AppendFormat("Export(\"");
                foreach (var v in list)
                {
                    sb.AppendFormat("{0}:", v.paramName);
                }
                sb.AppendLine("\")]");
                sb.Append("\t");
                sb.AppendFormat("{0} ", reType);

                string paramType = "";
                for (int i = 0; i < list.Count; i++)
                {

                    paramType = list[i].paramType;
                    if (BindBlock.CanParse(list[i].paramType))
                    {
                        if (i == 0)
                        {
                            paramType = string.Format("{0}Callback", functionName);
                        }
                        else
                        {
                            paramType = string.Format("{0}{1}Callback", functionName, list[i].paramName);
                        }
                        string delegateCode;
                        BindBlock.GenerateCSharp(paramType, list[i].paramType, out delegateCode);
                        this.DelegateCodeList.Add(delegateCode);
                    }

                    if (i > 0)
                    {
                        sb.AppendFormat(",{0} {1}", paramType, list[i].paramValue);
                    }
                    else
                    {
                        sb.AppendFormat("{0}({1} {2} ", functionName, paramType, list[i].paramValue);
                    }
                }

                sb.AppendLine(");");
            }

            return sb.ToString();
        }

        class methodNameParam
        {
            public string paramName { get; set; }
            public string paramType { get; set; }
            public string paramValue { get; set; }
        }

    }
}
